using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;

namespace Core.Scripting
{
    public static class CodeExecutor
    {
        static private int assemblyCounter = 0;

        static public Exception someObject = new Exception();

        static public void Execute(
            string code,
            Object game,
            out CompilerErrorCollection errors)
        {
            errors = null;

            if (code.Length == 0) return;

            AppDomain domain = AppDomain.CurrentDomain;
            Assembly[] assemblies = domain.GetAssemblies();

            CodeDomProvider provider = CSharpCodeProvider.CreateProvider("C#");
            CompilerParameters parameters = new CompilerParameters();
            parameters.CompilerOptions = "/target:library /optimize";
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            parameters.IncludeDebugInformation = false;

            foreach (Assembly loadedAssembly in assemblies)
            {
                string filename = loadedAssembly.CodeBase;
                filename = filename.Remove(0, 8);
                parameters.ReferencedAssemblies.Add(filename);
            }

            CompilerResults results = provider.CompileAssemblyFromSource(
                parameters,
                "using System;" +
                "using Microsoft.Xna.Framework;" +
                "using MyGameNamespace;" +
                "namespace JunkNamespace" + assemblyCounter + "{ public class JunkClass { public void JunkMethod(Object o) { MyGame game = (MyGame)o; " +
                code +
                "; } } }");

            if (results.Errors.Count != 0)
            {
                errors = results.Errors;
            }
            else
            {
                RunJunkMethod(results.CompiledAssembly, game);
            }

            provider.Dispose();
        }

        static private void RunJunkMethod(Assembly assembly, Object game)
        {
            try
            {
                Module[] mods = assembly.GetModules(false);
                Type[] types = mods[0].GetTypes();
                Object[] parameters = new Object[1];
                parameters[0] = game;

                Object o = Activator.CreateInstance(types[0]);
                MethodInfo mi = types[0].GetMethod("JunkMethod");
                mi.Invoke(o, parameters);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
            }
        }
    }
}
